const fs = require("fs");
const socketClass = {};
//首次加载服务类，用于队列
function loadService(app) {
  const fileBase = __dirname + "/../../../";
  const socketFileExists = fs.existsSync(fileBase + "socket");
  if (socketFileExists) {
    require("young-require-all")({
      dirname: fileBase + "socket",
      filter: /(.+)\.ts$/,
      resolve: function (Service) {
        for (let ServiceName in Service) {
          let name = Service[ServiceName].name;
          app.socket[name] = new Service[ServiceName](app);
        }
      },
    });
  }
}
async function socketInit(app) {
  if (!app.config.socket) return;
  if (typeof app.config.socket == "object" && !app.config.socket.status) return;
  app.socket = {};
  loadService(app);
  const server = require("http").createServer(app.callback());
  const io = require("socket.io")(server);
  //监听connect事件
  io.on("connection", async (socket) => {
    const query = socket.handshake.query;
    const className = query.c + "Socket";
    if (query.c && app.socket[className]) {
      const classLoad = app.socket[query.c + "Socket"];
      //通知客户端已连接
      if ("connected" in classLoad) {
        const data = await classLoad.connected(socket, io);
        if (data)
          socket.emit(
            "data",
            typeof data == "string" ? data : JSON.stringify(data)
          );
      }
      //监听disconnect事件
      socket.on("disconnect", async () => {
        if ("disconnect" in classLoad) {
          await classLoad.disconnect(socket, io);
        }
      });
      //监听事件
      if (socketClass[className] && socketClass[className].length) {
        for (const event of socketClass[className]) {
          socket.on(event, async (msg) => {
            const data = await classLoad[event](msg, socket, io);
            if (data)
              socket.emit(
                event,
                typeof data == "string" ? data : JSON.stringify(data)
              );
          });
        }
      }
    }
  });
  return server;
}
function socketEvent() {
  return function (targetClass, func) {
    const className = targetClass.constructor.name;
    if (!socketClass[className]) {
      socketClass[className] = [];
    }
    socketClass[className].push(func);
    return;
  };
}
module.exports = { loadService, socketInit, socketEvent };
